
module tagman_dm
#(
    parameter WAY_DEPTH=16
    ,INDEX_WID = ((WAY_DEPTH > 1) ? $clog2(WAY_DEPTH) : 1)
    ,TAG_WID=14//1K per page
    ,WBACK_ENABLE=1'b0 //this actually heavily depends on optimization
)
(
    input clk,
    input rst,
    input entry_read,   //Core interface
    input entry_wthru,
    input entry_wback,
    input [TAG_WID-1:0]address_tag,
    input [INDEX_WID-1:0]address_index,	
    input dfence_en,
    input valid_clear, //flush
    //input [TAG_WID-1:0]refill_tag,//BIU interface

    input fill_finish, //cachemem write, confirm refill valid
    input writeback_ok, //Writeback finished
    output line_miss,//refill request
    output replace_dirty, //page dirty, need to write back first
    output [TAG_WID-1:0]writeback_addr,//When D Fence, the address of valid dirty line to write back
    output [INDEX_WID-1:0]writeback_index
    //output [INDEX_WID-1:0]entry_replace_sel, //for replace select& dirty flush select
    //output [INDEX_WID-1:0]entry_select_addr//addr for access 
);
integer i,j,k;
reg [WAY_DEPTH-1:0]TagValidRegArray;
reg [TAG_WID-1:0]TagMemArray[WAY_DEPTH-1:0];
wire [TAG_WID-1:0]AccessTag;
wire entry_hit;
//对于CPU访存提供写穿透策略/写回策略接口，配套了内存同步控制线。
assign AccessTag = TagMemArray[address_index];
assign line_miss = (entry_read|entry_wback|entry_wthru) & (entry_hit==0);
assign entry_hit = (AccessTag == address_tag) & TagValidRegArray[address_index];
always@(posedge clk or posedge rst)//Tag management
begin
    if(rst)
        TagValidRegArray	<=	0;
    else
        if( valid_clear ) //clear valid bit
            TagValidRegArray<=	0;
        else if(fill_finish)
            TagValidRegArray[address_index]	<=	1'b1; 
        else
            TagValidRegArray<=TagValidRegArray;
end

always@(posedge clk or posedge rst)
    if(rst)
        for(k=0;k<WAY_DEPTH;k=k+1)
        TagMemArray[k]	=	0;
    else if(fill_finish)
        TagMemArray[address_index]	=	address_tag;
    else
        TagMemArray[address_index]	=	TagMemArray[address_index];

generate if(WBACK_ENABLE) 
begin : WBACK_REGS
    reg [WAY_DEPTH-1:0]TagDirtyRegArray;
    wire [WAY_DEPTH-1:0]DirtyInfoForCmp;
    assign DirtyInfoForCmp=(TagDirtyRegArray & TagValidRegArray);
    always@(posedge clk or posedge rst)
    begin
        if(rst)
        for(i=0;i<WAY_DEPTH;i=i+1)
            TagDirtyRegArray[i]   <=  0;
        else if (writeback_ok) //dirty page synced,we can move forward
        begin
            TagDirtyRegArray[writeback_index]   <=  0;
        end
        else if(entry_wback&entry_hit) 
        begin
            TagDirtyRegArray[address_index]<=1'b1;
        end
    end
    
    reg [INDEX_WID-1:0]IndexDirtyEncode[WAY_DEPTH-1:0];
    always @(*) 
    begin
        IndexDirtyEncode[0]=0;
        for(j=1;j<WAY_DEPTH;j=j+1)
            IndexDirtyEncode[j]=set_encode_cell(IndexDirtyEncode[j-1],j,DirtyInfoForCmp[j]);
    end
    
    //可扩展优先编码器：如果该位为1,返回该位所在编号,如果该位为0，传递上一级输入编号
    function [INDEX_WID-1:0]set_encode_cell;
        input [INDEX_WID-1:0]prev_set_num;
        input [INDEX_WID-1:0]cur_set_num;
        input cur_set_bit;
        begin
            set_encode_cell=(cur_set_bit)?cur_set_num:prev_set_num;
        end
    endfunction
    assign replace_dirty=(dfence_en)?(DirtyInfoForCmp!=0):DirtyInfoForCmp[address_index];//拟定替换cache line脏不？
    assign writeback_index=(dfence_en)?IndexDirtyEncode[WAY_DEPTH-1]:address_index;
    assign writeback_addr=TagMemArray[writeback_index];
end
else
begin:WRITE_THROUGH
    assign replace_dirty=1'b0;
    assign writeback_index=0;
    assign writeback_addr=0;
end
endgenerate
//写回管理
endmodule